<?php
/**
 * Класс для работы с массивами
 *
 * @author Дмитрий Кузьма <kouzma.d@gmail.com>
 * @version 1.0
 */

class Service_ArrayConverter {

  /**
   * Конвертирует обычный двумерный массив в дерево согласно ссылкам данного массива
   *
   * @param array $arrIn - двумерный массив
   * @param string $idName - название идентификатора, например 'ID_in'
   * @param string $rootName - название указателя на корневой элемент, например 'root_in'
   * @param mixed $absRootId - идентификатор корня дерева. По умолчанию null
   * @return array
   */
  public static function convertToTreeArray($arrIn, $idName, $rootName, $absRootId = null) {
  	
    $arrOut = array();
    $arrLink = array();
    do {
    	$changed = false;
    	$arrSize = sizeof($arrIn);
  	  $arrUnsort = array();
	    for ($i = 0; $i < $arrSize; $i++) {
	    	$id = $arrIn[$i][$idName];
	      $root = $arrIn[$i][$rootName];
        if ($root == $absRootId) {
          $arrOut[] = $arrIn[$i];
          $arrLink[$id] = &$arrOut[(sizeof($arrOut) - 1)];
          $changed = true;
        }
        else {
          if (isset($arrLink[$root])) {
            $arrLink[$root]['children'][] = $arrIn[$i];
            $arrLink[$id]= &$arrLink[$root]['children'][(sizeof($arrLink[$root]['children']) -1)];
	          $changed = true;
	        }
	        else $arrUnsort[] = $arrIn[$i];
	      }
	    }
	    $arrIn = $arrUnsort;
    } while(sizeof($arrUnsort) && $changed);
    return $arrOut;
  }
  
  /**
   * Конвертирует обычный двумерный массив в дерево согласно ссылкам данного массива
   * Учитывет то, что один и тот же элемент может посторяться в нескольких местах
   *
   * @param array $arrIn - двумерный массив
   * @param string $idName - название идентификатора, например 'ID_in'
   * @param string $rootName - название указателя на корневой элемент, например 'root_in'
   * @return array
   */
  public static function convertToTreeArrayWithRepeats($arrIn, $idName, $rootName, $sectionId) {
  	
    $arrOut = $arrIn;
    do {
    	$arrLeafs = array();
    	foreach ($arrOut as $rowNumber => $arrRow) {
    		$arrLinks[$arrRow[$idName]] = &$arrOut[$rowNumber];
    		if (!$arrRow[$rootName]) continue; // С корнем ничего не делаем
    		$isLeaf = true; 
      		foreach ($arrOut as $arrRowCompare) { // Проверяем, лист ли это
      			if ($arrRow[$idName] == $arrRowCompare[$rootName] || $arrRow[$rootName] == -$sectionId) {
      				$isLeaf = false;
      				break;
      			}
      		}
    		if ($isLeaf) $arrLeafs[] = $arrRow;
    	}
    	if ($arrLeafs) { // Проверяем, нашлись ли листья
    		foreach ($arrLeafs as $leaf) {
    			foreach ($arrOut as $rowNumber => $arrRow) {
    				if ($leaf[$rootName] == $arrRow[$idName]) $arrOut[$rowNumber]['children'][] = $leaf;
    				elseif ($leaf[$idName] == $arrRow[$idName]) unset($arrOut[$rowNumber]);
    			}
    		}
    	}
    } while($arrLeafs);
    return $arrOut;
  }  
  
  /**
   * Конвертирует обычный двумерный массив в дерево согласно ссылкам данного массива
   * Учитывет то, что один и тот же элемент может посторяться в нескольких местах
   *
   * @param array $arrIn - двумерный массив
   * @param string $idName - название идентификатора, например 'ID_in'
   * @param string $rootName - название указателя на корневой элемент, например 'root_in'
   * @return array
   */
  public static function convertToTreeArrayWithRepeatsOnlyCategories($arrIn, $idName, $rootName, $sectionId) {
  	
    $arrOut = $arrIn;
    do {
    	$hasBranches = false;
    	$arrLeafs = array();
    	foreach ($arrOut as $rowNumber => $arrRow) {
    		$arrLinks[$arrRow[$idName]] = &$arrOut[$rowNumber];
    		if (!$arrRow[$rootName]) continue; // С корнем ничего не делаем
    		$isLeaf = true; 
    		foreach ($arrOut as $arrRowCompare) { // Проверяем, лист ли это
    			if($arrRow[$idName] == $arrRowCompare[$rootName]) {
    				$hasBranches = true;
    				$isLeaf = false;
    				break;
    			}
    		  elseif ($arrRow[$rootName] == -$sectionId && $arrRow['is_category']) {
    			  $isLeaf = false;
    			  break;
    			}    			
    		}
    		if ($isLeaf) $arrLeafs[] = $arrRow;
    	}
    	if ($arrLeafs) { // Проверяем, нашлись ли листья
    		foreach ($arrLeafs as $leaf) {
    			foreach ($arrOut as $rowNumber => $arrRow) {
    				if ($leaf[$rootName] == $arrRow[$idName] && $leaf['is_category']) $arrOut[$rowNumber]['children'][] = $leaf;
    				elseif ($leaf[$idName] == $arrRow[$idName]) unset($arrOut[$rowNumber]);
    			}
    		}
    	}
    } while($arrLeafs);
    return $arrOut;
  }  
  

  /**
   * Функция сортирует элементы древовидного массива согласно заданному полю
   *
   * @param array $arrIn - древовидный массив
   * @param string $sortFieldName - поле, по которому следует сортировать
   * @return array - отсортированный массив
   */
  public static function sortTreeArray($arrIn, $sortFieldName = 'sort_num') {
  	
  	if (empty($arrIn)) return array();
  	$arrIn = array_values($arrIn);	
    $tempSize = sizeof($arrIn);
    for ($i = 0; $i < $tempSize; $i++) // сортируем вложенные массивы
    	if ( isset($arrIn[$i]['children']) )
    	  $arrIn[$i]['children'] = self::sortTreeArray($arrIn[$i]['children'], $sortFieldName);
    for ($i = 0; $i < $tempSize; $i++) // сортируем основной массив
      for ($j = $i; $j < $tempSize; $j++)
    		if ($arrIn[$j][$sortFieldName] < $arrIn[$i][$sortFieldName]) {
    			$temp = $arrIn[$i];
    		  $arrIn[$i] = $arrIn[$j];
    		  $arrIn[$j] = $temp;
    		}
    return $arrIn;
  }

  /**
   * Функция сортирует элементы массива согласно заданному полю
   *
   * @param array $arrIn - массив
   * @param string $sortFieldName - поле, по которому следует сортировать
   * @param $sortDirection - направление сортировки
   * @return array - отсортированный массив
   */
  public static function sortArray($arrIn, $sortFieldName, $sortDirection = 'ASC') {
  	$tempSize = sizeof($arrIn);
    for ($i = 0; $i < $tempSize; $i++) {
      for ($j = $i; $j < $tempSize; $j++) {
    		if (($arrIn[$j][$sortFieldName] < $arrIn[$i][$sortFieldName] && $sortDirection == 'ASC') || ($arrIn[$j][$sortFieldName] > $arrIn[$i][$sortFieldName] && $sortDirection == 'DESC')) {
    			$temp = $arrIn[$i];
    		  $arrIn[$i] = $arrIn[$j];
    		  $arrIn[$j] = $temp;
    		}
      }
    }
    return $arrIn;
  }

  /**
   * Возвращаем колонку из двумерного массива
   *
   * @param array $arrIn - двумерный массив
   * @param mixed $columnName - название или номер колонки, которую нужно вернуть
   * @return array - одномерный массив, соответствующий колонке входного
   */
  public static function getColumn($arrIn, $columnName) {
  	
  	if (empty($arrIn)) return array();
	  $arrColumn = array();
	  foreach ($arrIn as $arrElement) {
	    $arrColumn[] = $arrElement[$columnName];
	  }
	  return $arrColumn;
  }
  
  /**
   * Метод вычленяет колонку из двумерного массива и возвращает ее в строковом виде через разделитель
   *
   * @param array $arrIn - двумерный массив
   * @param mixed $columnName - название или номер колонки, которую нужно вернуть
   * @param mixed $glue - разделитель для возвращаемой строки
   * @return string - строка, соответствующая колнке входно массива
   */
  public static function getColumnAsString($arrIn, $columnName, $glue = ', ', $useIntval = false) {
		
    $strOut = '';
    if (empty($arrIn)) return null;
    $i = 0;
    foreach ($arrIn as $arrValue) {
      if ($i) $strOut .= $glue;
      $strOut .= $useIntval ? intval($arrValue[$columnName]) : $arrValue[$columnName];
      $i++;
    }
    return $strOut;
  }
  
  /**
   * Метод аналогичен методу implode, но обрабатывает одну колонку массива
   *
   * @param string $glue - разделитель
   * @param array $arrIn - двумерный массив
   * @param mixed $columnName - название или номер колонки, которую нужно вернуть
   * @return array - одномерный массив, соответствующий колонке входного
   */
  public static function implodeColumn($glue, $arrIn, $columnName) {
  	
    $strOut = '';
    $arrSize = sizeof($arrIn);
    if (!$arrSize) return $strOut;
    for ($i = 0; $i < $arrSize; $i++) {
    	$strOut .= $arrIn[$i][$columnName] . $glue;
    }
    return substr($strOut, 0, -strlen($glue));
  }

  /**
   * Из двух массивов формируем новый, содержащий элементы первого массива, которых нет во втором массиве
   *
   * @param array $arr1
   * @param array $arr2
   * @param boolean $strictLowerCase - строго, с понижением регистра
   * @return array
   */
  public static function arrayFullDifference($arr1, $arr2, $strictLowerCase = false, $specialchars = 0) {
    
    if (empty($arr2)) return $arr1;
    if ($specialchars == 2) $arr2 = array_map('htmlspecialchars', $arr2);
    $arrNotExists = array();
    if ($arr1) {
      foreach ($arr1 as $arr1Element) {
        $isArr1ElemInArr2 = false;
        if ($strictLowerCase) {
          if (!self::in_iarray(($specialchars == 1) ? htmlspecialchars($arr1Element) : $arr1Element, $arr2)) $arrNotExists[] = $arr1Element;
        }
        else {
          if (!in_array(($specialchars == 1) ? htmlspecialchars($arr1Element) : $arr1Element, $arr2)) $arrNotExists[] = $arr1Element;
        }
      }
    }
    return $arrNotExists;
  }

  /**
   * Метод проверяет элемент на вхождение в массив (без учета возмоэжной многомерности)
   *
   * @param mixed $val
   * @param array $arr
   * @return bool
   */
	public static function in_iarray($val, $arr) {
		
		if (!$arr) return false;
	  $arrSize = sizeof($arr);
	  for ($i = 0; $i < $arrSize; $i++){
	    if (Service_Function::strtolowerU($val) == Service_Function::strtolowerU($arr[$i])) return true;
	  }
	  return false;
	}
	/**
	 * Метод возвращает массив, идентичный переданному, но содержащий только уникальные в рамках массива элементы
	 *
	 * @param array $arr
	 * @return array
	 */
	public static function array_iunique($arr) {
		
	  $n = array();
	  $arrSize = sizeof($arr);
	  for ($i = 0; $i < $arrSize; $i++){
	    if (!self::in_iarray($arr[$i], $n)) $n[] = $arr[$i];
		}
	  return $n;
	}

	/**
	 * Метод делает из многоуровнего массива, массив основанный на ключах со второго уровня
	 *
	 * @param array $arrIn
	 * @param int $key
	 * @return array
	 */
	public static function makeKeyArrayFromMultyArray($arrIn, $key) {
		
		$arrReturn = array();
		for ($i = 0; $i < sizeof($arrIn); $i++) {
		  $arrReturn[$arrIn[$i][$key]] = $arrIn[$i];
		}
		return $arrReturn;
	}

	/**
	 * Метод делает из многоуровнего массива, массив основанный на ключах со второго уровня
	 * А в качестве значений подставляет из поля $field
	 *
	 * @param array $arrIn - Входной массив
	 * @param string $key - Поле в массиве, которое будет ключом выходного массива 
	 * @param string field - Поле в массиве, которое будет значением выходного массива 
	 * @return array
	 */
	public static function makeKeySimpleArrayFromMultyArray($arrIn, $key, $field) {
		
		$arrReturn = array();
		//for ($i = 0; $i < sizeof($arrIn); $i++) {
		foreach ($arrIn as $arrValue) {
		  $arrReturn[$arrValue[$key]] = $arrValue[$field];
		}
		return $arrReturn;
	}

	/**
	 * Из двух ассоциативных массивов формируем новый, содержащий элементы первого массива, которых нет во втором массиве
	 *
	 * @param array $arr1
	 * @param array $arr2
	 * @param string $strField1 - поле первого ассоциативного массива, по которому производится сравнение
	 * @param string $strField2 - поле второго ассоциативного массива, по которому производится сравнение
	 * @return array
	 */
	public static function getDataArraysFullDiff($arr1, $arr2, $strField1, $strField2) {
		
	  $arrNotExists = array();
	  foreach ($arr1 as $arr1Element) {
	    $isArr1ElemInArr2 = false;
	    foreach ($arr2 as $arr2Element) {
	      if ($arr1Element[$strField1] == $arr2Element[$strField2]) {
	        $isArr1ElemInArr2 = true;
	        break;
	      }
	    }
	    if (!$isArr1ElemInArr2) $arrNotExists[] = $arr1Element;
	  }
	  return $arrNotExists;
	}

  /**
   * Получаем среднее значение массива
   *
   * @param array of float|int $arr
   * @param string $fieldName - поле для извлечения (ассоциативный случай);
   * @return float
   */
  public static function getArrayAverageValue($arr, $fieldName = null) {
  	
		if (!sizeof($arr)) return null;
    if ($fieldName) $arr = Service_ArrayConverter::getArrayColumn($arr, $fieldName);
		return array_sum($arr) / sizeof($arr);
  }

  /**
   * Метод соединяет 2 массива хитрым образом
   * Первый массив (большой) имеет поле $strLinkColumn
   * Второй массив (малый) присоединяется к первом по связи с этим полем, формируя колонку $strCombineColumn
   *
   * @param array $arrBig
   * @param array $arrSmall
   * @param string $strLinkColumn
   * @param string $strCombineColumn
   * @param string $strKeyName
   * @param bool $removeLinkColumn = false
   */
  public static function combineArraysAndMakeKeys($arrBig, $arrSmall, $strLinkColumn, $strCombineColumn, $strKeyName, $removeLinkColumn = false) {
    
    if (!$arrSmall) return $arrBig;
    foreach ($arrSmall as $key => $row) {
      if ($row[$strLinkColumn] === null) $arrSmall[$key][$strLinkColumn] = 0;
    }
    
    $arrBigSize = sizeof($arrBig);
    for ($j = 0; $j < $arrBigSize; $j++) {
      foreach ($arrSmall as $i => $arrSmallIn) {
        if (isset($arrSmall[$i][$strLinkColumn]) && $arrSmall[$i][$strLinkColumn] == $arrBig[$j][$strLinkColumn]) {
        	$arrBig[$j][$strCombineColumn][$arrSmall[$i][$strKeyName]] = $arrSmall[$i];
        	if ($removeLinkColumn) {
        		unset($arrBig[$j][$strCombineColumn][$arrSmall[$i][$strKeyName]][$strLinkColumn]);
        		unset($arrBig[$j][$strCombineColumn][$arrSmall[$i][$strKeyName]][$strKeyName]);
        	}
        }
      }
    }
    return $arrBig;
  }
  
  /**
   * Метод соединяет 2 массива хитрым образом
   * Первый массив (большой) имеет поле $strLinkColumn
   * Второй массив (малый) присоединяется к первом по связи с этим полем, формируя колонку $strCombineColumn
   *
   * @param array $arrBig
   * @param array $arrSmall
   * @param string $strLinkColumn
   * @param string $strCombineColumn
   * @param bool $removeLinkColumn = false
   */
  public static function combineArrays($arrBig, $arrSmall, $strLinkColumn, $strCombineColumn, $removeLinkColumn = false, $oneToOne = false, $oneToOneField = '') {
    
    if (!$arrSmall) return $arrBig;
    foreach ($arrSmall as $key => $row) {
      if ($row[$strLinkColumn] === null) $arrSmall[$key][$strLinkColumn] = 0;
    }
    $arrBigSize = sizeof($arrBig);
    $arrSmallSize = sizeof($arrSmall);
    //for ($j = 0; $j < $arrBigSize; $j++) {
    foreach ($arrBig as $bigKey => $bigValue) {
      //for ($i = 0; $i < $arrSmallSize; $i++) {
      foreach ($arrSmall as $i => $arrSmallIn) {
        if (isset($arrSmall[$i][$strLinkColumn]) && $arrSmall[$i][$strLinkColumn] == $arrBig[$bigKey][$strLinkColumn]) {
          if ($removeLinkColumn) unset($arrSmall[$i][$strLinkColumn]);
        	if (is_numeric($i)) {
        	  if ($oneToOne) $arrBig[$bigKey][$strCombineColumn] = $arrSmall[$i][$oneToOneField]; 
        	  else $arrBig[$bigKey][$strCombineColumn][] = $arrSmall[$i];
        	}
        	else $arrBig[$bigKey][$strCombineColumn][$i] = $arrSmall[$i];
        }
      }
    }
    return $arrBig;
  }  
  
  public static function combineArraysQuick($arrBig, $arrSmall, $strLinkColumn, $strCombineColumn, $test = false) {
  	/*echo '<pre>';
  	var_dump(func_get_args());
  	echo '</pre>';*/
  	
    if (!$arrSmall) return $arrBig;
    if (!$arrBig) return $arrBig;
    foreach ($arrSmall as $arrSmallIn) {
    	foreach ($arrBig as &$bigValue) {
    		if ($arrSmallIn[$strLinkColumn] == $bigValue[$strLinkColumn]) {
    			$bigValue[$strCombineColumn][] = $arrSmallIn;
    			break;
    		}
    	}
    }
    return $arrBig;
  }
  
  /**
   * Добавляем поля из одного массива в другой по совпадению определенных ключей 
   * 
   * @param array $arrBig - Массив к которому добавляем поля
   * @param array $arrSmall - Массив из которого берем поля
   * @param string $strLinkFrom - Ключ первого массива для поиска соответствия
   * @param string $strLinkTo - Ключ второго массива для поиска соответствия
   * @param array $arrFieldsToCopy - Массив полей для копирования (ключ - поле во втором, значение - поле во первом)
   */
  public static function combineArraysAddFields(array $arrBig, array $arrSmall, $strLinkFrom, $strLinkTo, array $arrFieldsToCopy) {
  	
  	$arrBigSize = sizeof($arrBig);
  	$arrSmallSize = sizeof($arrSmall);
		for ($j = 0; $j < $arrBigSize; $j++) {
			for ($i = 0; $i < $arrSmallSize; $i++) {
				if (isset($arrSmall[$i][$strLinkFrom]) && $arrSmall[$i][$strLinkFrom] == $arrBig[$j][$strLinkTo]) {
					foreach ($arrFieldsToCopy as $fromCopyField => $toCopyField) {
				    $arrBig[$j][$toCopyField] = $arrSmall[$i][$fromCopyField];
					}
			    break;
				}
			}
			foreach ($arrFieldsToCopy as $fromCopyField => $toCopyField) {
				if (!isset($arrBig[$j][$toCopyField])) $arrBig[$j][$toCopyField] = 0;
			}
		}
		return $arrBig;
  }
  
  /**
   * Метод соединяет 2 массива хитрым образом
   * Первый массив (большой) имеет поле $idName (предположительно названи ID в БД)
   * Второй массив на первом уровне имеет числовые индексы. Он присоединяется соединяя числовой индекс с ID большого массива
   * Присоединение записывается в новое поле большого массива $strCombineColumn
   *
   * @param array $arrBig
   * @param array $arrSmall
   * @param string $idName
   * @param string $strCombineColumn
   */
  public static function addIdsArray($arrBig, $arrSmall, $idName, $strCombineColumn) {
  	
  	$arrBigSize = sizeof($arrBig);
  	$arrSmallSize = sizeof($arrSmall);
		for ($i = 0; $i < $arrBigSize; $i++) {
		  $curId = $arrBig[$i][$idName];
			foreach ($arrSmall as $smallKey => $smallElement) {
				if ($smallKey == $curId) {
					$arrBig[$i][$strCombineColumn] = $smallElement;
					break;
				}
			}
		}
		return $arrBig;
  }
  /**
   * Метд преобразовывает массив с ключами к обычному (если ключей нет во внутренней структуре массива, то они пропадут)
   *
   * @param array $arrKey
   * @return array
   */
  public static function makeUsualArrayFromKeyArray($arrKey) {
  	
  	$arrReturn = array();
  	foreach ($arrKey as $record) {
  		$arrReturn[] = $record;
  	}
  	return $arrReturn;
  }

  /**
   * Метод производит сортировку по нескольким полям массива
   *
   * @param array $arrToSort
   * @param array $arrColumns - ассоциативный массив полей для сортировки, ключом является поле, а значением - направление
   * @return array
   */
  public static function sortMultyColumns($arrToSort, $arrColumns) {
  	
		$arrReturn = $arrToSort;
  	for($i = 0; $i < sizeof($arrReturn); $i++) {
  		for ($j = $i; $j < sizeof($arrReturn); $j++) {
  			foreach ($arrColumns as $sortColumn => $sortType) {
				  if ($arrReturn[$i][$sortColumn] > $arrReturn[$j][$sortColumn] && $sortType == 'desc') break;
  				elseif ($arrReturn[$i][$sortColumn] < $arrReturn[$j][$sortColumn] && $sortType == 'asc') break;
				  elseif ($arrReturn[$i][$sortColumn] != $arrReturn[$j][$sortColumn]) {
				  	$temp = $arrReturn[$i];
				  	$arrReturn[$i] = $arrReturn[$j];
				  	$arrReturn[$j] = $temp;
				  	break;
				  }
  			}
  		}
  	}
  	return $arrReturn;
  }

  /**
   * Метод объединяет и сортирует переданные массивы по полю 'sort_num'
   *
   * @param array $arrInputs - массивы для объединения и сортировки в формате: array(0=>array1(0=>'', 1=>'', 2=>'', ...), 1=>array2(0=>'', 1=>'', 2=>'', ...), 2=>array3(0=>'', 1=>'', 2=>'', ...) ...)
   */
  public static function mergeAndSortArrays($arrInputs) {
    
    $arrResult = array();
    $size = sizeof($arrInputs); // сколько массивов надо объединить
    for ($i = 0; $i < $size; $i++) {
      $arrInSize = sizeof($arrInputs[$i]);
      for ($j = 0; $j < $arrInSize; $j++) {
        $arrResult[] = $arrInputs[$i][$j];
      }
    }
    return self::sortTreeArray($arrResult, 'sort_num'); // сортровка блоков по возрастанию
  }

  /**
   * Метод создает новый массив из исходного преобразуя названия полей
   *
   * @param array $arrStart
   * @param array $arrFieldToCopy
   * @return array
   */
  public static function createArrayWithNewFields($arrStart, $arrFieldToCopy) {
  	
  	$arrReturn = array();
  	if ($arrFieldToCopy && $arrStart) {
  		$i = 0;
  		foreach ($arrStart as $element) {
  			foreach ($arrFieldToCopy as $keyTo => $keyFrom) {
  				if (isset($element[$keyFrom])) $arrReturn[$i][$keyTo] = $element[$keyFrom];
  				else $arrReturn[$i][$keyTo] = null;
  			}
  			if (isset($element['children'])) $arrReturn[$i]['children'] = self::createArrayWithNewFields($element['children'], $arrFieldToCopy);
  			$i++;
  		}
  		return $arrReturn;
  	}
  	else return null;

  }

  /**
   * Изменяет поля в основном массиве полями из второго, если равны поля с ключом $conditionField
   *
   * @param array $arrInput
   * @param array $arrUpdatedFields
   * @param string $conditionField
   * @return array
   */
  public static function updateFieldsInAssocArrayWithConditions($arrInput, $arrUpdatedFields, $conditionField) {
    
    $sizeUpdatedFields = sizeof($arrUpdatedFields);
    $sizeBaseArray = sizeof($arrInput);
    for ($j = 0; $j < $sizeUpdatedFields; $j++) {
      for ($i = 0; $i < $sizeBaseArray; $i++) {
        if ($arrUpdatedFields[$j][$conditionField] == $arrInput[$i][$conditionField]) {
          $arrInput[$i] = $arrUpdatedFields[$j];
        }
      }
    }
    return $arrInput;
  }

  /**
   * Метод проверяет, находится ли некоторый элемент в массиве
   *
   * @param array $arr
   * @param mixed $value
   * @return bool
   */
  public static function isInArray($arr, $value) {
  	
  	for ($i = 0; $i < sizeof($arr); $i++) {
  	  if ($arr[$i] == $value) return true;
  	}
  	return false;
  }

  /**
   * Удаляем все пустые элементы массив (сбрасываем при этом индексы)
   *
   * @param array $arr
   * @return array
   */
  public static function removeEmptyElements($arr) {
  	
    if (empty($arr)) return array();
    foreach ($arr as $key => $value) {
      if (empty($value)) {
        unset($arr[$key]);
      }
    }
    return array_values($arr);
  }

  /**
   * Заменяем ключи в массиве
   *
   * @param array $arr - Исходный массив
   * @param array $arrOldKeys - список старых ключей к замене
   * @param array $arrNewKeys - список новык ключей (соответственно)
   * @return array
   */
  public static function renameKeys($arrIn, $arrOldKeys, $arrNewKeys) {
  	
    foreach ($arrIn as $key => $arrElement) {
      $size = sizeof($arrOldKeys);
      for ($i = 0; $i < $size; $i++) {
        unset($arrIn[$key][$arrOldKeys[$i]]);
        $arrIn[$key][$arrNewKeys[$i]] = $arrElement[$arrOldKeys[$i]];
      }
    }
    return $arrIn;
  }

  /**
   * Удаляет ключи из массива
   *
   * @param $array - исходный массив
   * @param $arrKeys - массив с ключами
   * @return массив
   */
  public static function deleteFromArray($array, $arrKeys) {
  	
  	foreach ($arrKeys as $key) {
  		if (isset($array[$key])) unset($array[$key]);
  	}
  	return $array;
  }
  
  /**
   * Убирает из массива лишние строки в соответствии с набором идентификаторов
   * 
   * @param array $arrayBig - многомерный массив, из которого необходимо убрать лишнее
   * @param array $arrIdsToDelete - одномерный массив, содержащий идентификаторы элементов, которые нужно убрать
   * @param string $fieldName - поле, по которому производится сравнение - типично, первичный ключ таблицы
   */
  public static function removeRowsByIds($arrayBig, $arrIdsToDelete, $fieldName) {
    
    $arrRet = array();
    if (!$arrayBig) return $arrRet;
    if (!$arrIdsToDelete) return $arrayBig;
    foreach ($arrayBig as $row) {
    	foreach ($arrIdsToDelete as $idToDelete) {
    		if ($row[$fieldName] == $idToDelete) continue 2;
    	}
    	$arrRet[] = $row;
    }
    return $arrRet;
  }
  
  /**
   * Метод формирует массив, в котором оставлены только определенные колонки исходного массива
   * 
   * @param array $arrIn - многомерный массив, из которого будут браться колонки
   * @param array $arrColumns - массив с названиями столбцов, которые нужно вернуть
   */
  public static function getColumnsOfMultyArray($arrIn, $arrColumns) {
    
  	if (!$arrColumns || !$arrIn) return array();
  	$arrRet = array();
  	foreach ($arrIn as $key => $row) {
  		$arrRet[$key] = array();
  		foreach ($arrColumns as $columnName) {
  			if (isset($row[$columnName])) $arrRet[$key][$columnName] = $row[$columnName];
  		}
  	}
  	return $arrRet;
  }
  
  /**
   * Метод формирует массив, в котором оставлены только определенные колонки исходного массива
   * 
   * @param array $arrIn - массив, из которого будут браться колонки
   * @param array $arrColumns - массив с названиями столбцов, которые нужно вернуть
   */
  public static function getColumnsOfArray($arrIn, $arrColumns) {
    
  	if (!$arrColumns || !$arrIn) return array();
  	$arrRet = array();
  	foreach ($arrColumns as $columnName) {
  		if (isset($arrIn[$columnName])) $arrRet[$columnName] = $arrIn[$columnName];
  	}
  	return $arrRet;
  }

  /**
   * Убираем пустые значения из массива
   * 
   * @param $arrIn - входной массив
   */
  public static function unsetEmptyValues($arrIn) {
    
  	foreach ($arrIn as $key => $value) {
  		if (empty($value)) unset($arrIn[$key]);
  	}
  	return $arrIn;
  }
  
	/**
	 * Получает номер элемента 
	 * 
	 * @param array $arrIn
	 * @param string $fieldName
	 * @return mixed - номер строки, в которой найден элемент или false, если элемента нет
	 */
  public static function findFieldInMultyArray($arrIn, $fieldName) {
    
		if (!$arrIn) return false;
		foreach ($arrIn as $key => $arrIn) {
			if ($arrIn[$fieldName]) return $key;
		}
		return false;
	}
	
	/**
	 * Оставляем только уникальные значения
	 * 
	 * @param $arrIn - исходный массив
	 * @param $fieldName - поле массива по которому будет проверяться уникальность
	 */
	public static function unique($arrIn, $fieldName) {

	  $arrValues = array();
	  foreach ($arrIn as $key => $array) {
	    if (!in_array($array[$fieldName], $arrValues)) $arrValues[] = $array[$fieldName];
	    else unset($arrIn[$key]);
	  }
	  return $arrIn;
	}
	
	/**
	 * Возвращает элементы, у которых в поле определенное значение
	 * 
	 * @param array $arrIn - входящий многомерный массив
	 * @param string $fieldName - название поля, по которому производлится поиск
	 * @param string $search - поисковое значение
	 */
	public static function findRowsByField($arrIn, $fieldName, $search) {

		if (!$arrIn) return array();
		$arrOut = array();
		foreach ($arrIn as $row) {
			if ($row[$fieldName] == $search) $arrOut[] = $row;
		}
		return $arrOut;
	}
	
	/**
	 * Создает новый массив, разделенный по полю $fieldToSplit
	 * 
	 * @param array $arr - входящий многомерный массив
	 * @param string $fieldToSplit - название поля, значение которого будет выступать первичным ключом для нового массива
	 * @param string $fieldToInsert - поле, значениями которого будет наполняться возвращаемый массив
	 */
	public static function splitArrayByField(array $arrIn, $fieldToSplit, $fieldToInsert = null, $key = null) {

  	$arrOut = array();
  	foreach ($arrIn as $i => $row) {
	  	if ($fieldToInsert) $arrOut[$row[$fieldToSplit]][$i] = $row[$fieldToInsert];
	  	else {
	  	  if ($key) $arrOut[$row[$fieldToSplit]][$row[$key]] = $row; 
	  	  else $arrOut[$row[$fieldToSplit]][$i] = $row;
	  	}
	  }
	  return $arrOut;
	}
	/**
	 * Создает новый массив, разделенный по полю $fieldsToSplit
	 * 
	 * @param array $arr - входящий многомерный массив
	 * @param array $fieldsToSplit - названия поля, значение которого будет выступать первичным ключом для нового массива и далее подмассивов
	 */
	public static function splitArrayByFields(array $arrIn, array $fieldsToSplit) {

	  $fieldsToSplitFromEnd = array();
	  foreach ($fieldsToSplit as $fieldToSplit) $fieldsToSplitFromEnd[] = $fieldToSplit;
  	$arrOut = array();
  	
  	foreach ($arrIn as $i => $row) {
	  	$link = &$arrOut;
  		foreach ($fieldsToSplitFromEnd as $fieldToSplit) {
	  		$currentKey = $row[$fieldToSplit];
  			if (!isset($link[$currentKey])) $link[$currentKey] = array();
  			$link = &$link[$currentKey];
	  	}
	  	$link[] = $row;
  		//$arrOut[$row[$fieldToSplit1]][$row[$fieldToSplit2]][$row[$fieldToSplit3]][$i] = $row;
	  }
	  return $arrOut;
	}
	
	/**
	 * Удаляем листья древовидного массива
	 * 
	 * @param $arrIn - Древовидный массив элементов
	 */
	public static function unsetChildren($arrIn) {

	  $hasChildren = false;
	  foreach ($arrIn as $key => $arrRow) {
	    if (isset($arrRow['children'])) {
        $ret = self::unsetChildren($arrRow['children']);
        if (!$ret) unset($arrIn[$key]['children']);
        else $arrIn[$key]['children'] = $ret;
	      $hasChildren = true;
	    }
	    else unset($arrIn[$key]);
	  }
	  if (!$hasChildren) return false; 
	  else return $arrIn;
	}
	
	/**
	 * Конвертируем древоводиный массив в одномерный
	 * 
	 * @param array $arrIn - Древовидный массив
	 */
	public static function convertToListArray($arrIn) {

	  $arrReturn = array();
	  foreach ($arrIn as $arrElement) {
	    $arrReturn[] = $arrElement;
	    if (isset($arrElement['children'])) {
	      $arrReturn = array_merge($arrReturn, self::convertToListArray($arrElement['children']));
	    }
	  }
	  foreach ($arrReturn as $key => $arrElement) {
	    unset($arrReturn[$key]['children']);
	  }
	  return $arrReturn;
	}
	
	/**
	 * Вырезаем часть массива начиная со $start и количеством $amount 
	 * 
	 * @param array $arrIn - Входной массива
	 * @param int $start - Начальный элемент
	 * @param int $amount - Кол-во элементов
	 */
	public static function getArraySlice($arrIn, $start, $amount) {

	  $i = 0;
	  $finish = $start + $amount;
	  $arrReturn = array();
	  foreach ($arrIn as $key => $value) {
	    if ($i >= $start && $i < $start + $amount) {
	      $arrReturn[] = $arrIn[$key];
	    }
	    $i++;
	  }
	  return $arrReturn;
	}
	
	/**
	 * Оставляем в большом масссиве только те элементы, ID которых есть в массиве $arrIds 
	 * 
	 * @param array $arrIn - Массив элементов
	 * @param array $arrIds - Массив ID элементов 
	 * @param string $fieldName - Название поля содержащего ID
	 */
	public static function getElementsByIds($arrIn, $arrIds, $fieldName) {

	  $arrReturn = array();
	  foreach ($arrIn as $arrElement) {
	    if (isset($arrElement[$fieldName])) {
	      if (in_array($arrElement[$fieldName], $arrIds)) $arrReturn[] = $arrElement;
	    }
	  }
	  return $arrReturn;
	}
	
	/**
	 * Подсчитывает кол-во повторов каждого вхождения
	 * 
	 * @param array $arrIn - массив с повторами - array(2, 1, 3, 2, 1, 2)
	 * @return array - массив с кол-вом повторов - array(2 => 3, 1 => 2, 3 => 1)
	 */
	public static function getRepeats($arrIn) {
		
		$arrOut = array();
		foreach ($arrIn as $value) {
			if (isset($arrOut[$value])) $arrOut[$value]++;
		  else $arrOut[$value] = 1;
		}		
		return $arrOut;
	}
	
  /**
  * Создает массив ключ => значение из многомерного массива
  * 
  * @param array $arrIn - входящий массив
  * @param string $key - название поля, которое будет выступать в качестве ключа во входящем массиве
  * @param string $value - название поля, которое будет выступать в качестве значения во входящем массиве
  */
  public static function makeKeyValueArrayFromMultyArray($arrIn, $key, $value) {
    
    $retArray = array();
    for ($i = 0; $i < sizeof($arrIn); $i++) {
      $retArray[$arrIn[$i][$key]] = $arrIn[$i][$value];
    }
    return $retArray;
  }
  
  /**
   * Рекурсивно обходит незамкнутый массив, ищет ключи, оканчивающиеся на _en или _ru, создает на их основе беcсуффиксные (берется текущий язык), а оригинальные ключи удаляет
   * @param array $arr
   */
 /* public static function i18filter(&$arr) {
  
  	array_walk($arr, function(&$val, $key, &$arr) {
  		
  		if(is_array($val)) {
  			Service_ArrayConverter::i18filter($val);
  			return;
  		}

  		if(!is_string($val)) return;
	
  		if(!preg_match('/(.*)_(en|ru)$/', $key, $m)) return;
  		
  		$val = trim($val);
  		$newKey = $m[1];
  		$good = $m[2] == Service_Translate::getLang();
  
  		//any, default. Usually english
  		if(@!$arr[$newKey]) $arr[$newKey] = $val;
  
  		//primary, main lang
  		if($good && $val) $arr[$newKey] = $val;
  
  		unset($arr[$key]);
  	}, &$arr);
  }
  */
  
  /**
   * Рекурсивная замена в массиве
   * 
   * @param string $search - Что ищем
   * @param string $replace - На что заменяем
   * @param mixed $element - Элемент для поиска
   */
	public static function arrayStrReplace($search, $replace, $element) {
  	if (is_array($element)) {
    	foreach ($element as $key => $subElement) {
	      $element[$key] = self::arrayStrReplace($search, $replace, $subElement);
    	}
    	return $element;
		} 
		return str_replace($search, $replace, $element);
  }
  
}
?>